/*------------------------------------------------------------------------------
$module:      CseObj
$package:     CseApi
$purpose:     C++ wrap for CSE Data type
$author:      WAYNE WORK STDIO
$CreateAt:    08/07/04
$LastModify:
$license:     Mozilla Public License Version 1.1
------------------------------------------------------------------------------*/

#include "CseApi_.h"

#ifdef _DEBUG
TInt32 TotalCseObjCount = 0;
#endif

// Following define TCseObj
//==============================================================================
STATIC TCseException LogObjBuildErr()
{
    return LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("illegal CSE object build flag"));
}

// format for CSE object build
//------------------------------------------------------------------------------
// v: CSE-variant i: CSE-int  w: CSE-wint  f: CSE-float  s: CSE-str   S: N-str
// t: CSE-tier    T: N-tier   b: CSE-buff  B: N-buff     d: CSE-dict  D: N-dict
//
// %#: CSE-ID     %@: CSE-Notator    %-: CSE-weak    %+: CSE-strong
//
// (: CSE-tier begin           ): CSE-tier end
// [: CSE-buff begin           ]: CSE-buff end
// {: CSE-dict begin           }: CSE-dict end
// <: CSE-notator begin        >: CSE-notator end
// <>: CSE-instance
STATIC TXchar BuildOneCseObj(TStolenObj& owner, TXchar prefix, TXchar flag, va_list& pArg)
{
    if (_T('%') == prefix)
    {
        if (_T('#') == flag)         // CSE id
            owner = CseId_NewEx(TCharArray(va_arg(pArg,const TXchar *)));
        else if (_T('@') == flag)    // CSE notator
            owner = CseNotator_new(va_arg(pArg,CseObj));
        else if (_T('+') == flag)    // CSE strong
            owner = CseStrong_new(va_arg(pArg,CseObj));
        else if (_T('-') == flag)    // CSE weak
            owner = CseWeak_new(va_arg(pArg,CseObj));

        // %c: int8    %C: uint8   %h: int16  %H: uint16  %d: int32  %D: uint32
        // %w: int64   %W: uint64  %f: float  %F: double  %i: TInt   %I: TUint
        // %u: wchar   %U: wchar*  %x: TXchar %X: TXchar* %V: void*
        else owner = CseInstance_MapVar(flag,pArg);
    }
        
    else if (_T('v') == flag)    // CSE variant
        owner = Cse_IncRefEx(va_arg(pArg,CseObj));
    else if (_T('i') == flag)    // CSE int
        owner = CseInt_new(va_arg(pArg,TInt));
    else if (_T('s') == flag)    // CSE str
        owner = CseStr_new(TCharArray(va_arg(pArg,const TXchar *)));
    else if (_T('S') == flag)    // CSE N-str
    {
        TInt32 i = va_arg(pArg,TInt32);
        owner = CseStr_new(TCharArray(va_arg(pArg,const TXchar *),i));
    }
    else if (_T('t') == flag)    // CSE tier
        owner = CseTier_new(0);
    else if (_T('T') == flag)    // CSE N-tier
    {
        TInt32 i = va_arg(pArg,TInt32);
        owner = CseTier_new(i);
    }
    else if (_T('b') == flag)    // CSE buff
        owner = CseBuff_new(0);
    else if (_T('B') == flag)    // CSE N-buff
    {
        TInt32 i = va_arg(pArg,TInt32);
        owner = CseBuff_new(i);
    }
    else if (_T('d') == flag)    // CSE dict
        owner = CseDict_new(8);
    else if (_T('D') == flag)    // CSE N-dict
    {
        TInt32 i = va_arg(pArg,TInt32);
        owner = CseDict_new(i);
    }
    else if (_T('w') == flag)    // CSE wint
        owner = CseWint_new(va_arg(pArg,TInt64));
    else if (_T('f') == flag)    // CSE float
		owner = CseFloat_new(va_arg(pArg,TDouble));

    else if (_T('[') == flag || _T('{') == flag || _T('(') == flag || _T('<') == flag)
    {
        owner = CseBuff_new(0);  // CSE buff, dict, tier, notator
        return flag;
    }
    else if (_T(']') == flag || _T('}') == flag || _T(')') == flag || _T('>') == flag)
        return flag;             // go back to uplevel

    else throw LogObjBuildErr();

    return _T('\0');
}

TCseObj::TCseObj()
{
    m_data = dummy;
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(CseObj obj)
{
    if (obj == NULL) obj = dummy;
    m_data = Cse_IncRefEx(obj);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TCseObj& obj)
{
    m_data = Cse_IncRefEx(obj.m_data);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

STATIC TInt CseNum_AsInt(CseObj obj)
{
    int tp = Cse_type(obj);
    if (dtInt == tp)
        return obj->iValue;
    else if (dtWint == tp)
        return (TInt) obj->wValue;
    else if (dtFloat == tp)
        return (TInt) obj->fValue;
    else return (TInt) obj;
}

STATIC CseObj SetupBuildResult(const TXchar flag, CseObj buff)
{
    ASSERT_TRUE(Cse_type(buff) == dtBuff);

    if (_T(']') == flag)
        return Cse_IncRefEx(buff);
    else if (_T('}') == flag)
    {
        TStolenObj ret = CseDict_new();
        int index = 1;
        int iLen = CSE_ARRAY_LEN(buff->bValue);
        while (index < iLen)
        {
            CseObj key = buff->bValue[index-1];
            CseDict_set(ret,key,buff->bValue[index]);
            index += 2;
        }
        return Cse_IncRefEx(ret);
    }
    else if (_T(')') == flag)
    {
        int iLen = CSE_ARRAY_LEN(buff->bValue);
        TStolenObj ret = CseTier_new(iLen);
        for (int index = 0; index < iLen; index++)
            ret->tValue[index] = CseNum_AsInt(buff->bValue[index]);
        return Cse_IncRefEx(ret);
    }
    else if (_T('>') == flag)
    {
        int iLen = CSE_ARRAY_LEN(buff->bValue);
        if (iLen <= 0)
            return CseInstance_new();
        else
        {
            TStolenObj ret = CseNotator_new(buff->bValue[0]);
            for (int index = 1; index < iLen; index++)
                CseBuff_append(ret,buff->bValue[index]);
            return Cse_IncRefEx(ret);
        }
    }
    else throw LogObjBuildErr();
}

STATIC CseObj CreateByFmt(const TXchar *format, va_list& pArg)
{
    // first try quick access for most common build
    const TXchar *pCh = format;
    TXchar ch = format[1];
    if (ch == _T(']') && *pCh == _T('['))
        return CseBuff_new(0);
    else if (ch == _T('}') && *pCh == _T('{'))
        return CseDict_new();
    else if (ch == _T(')') && *pCh == _T('('))
        return CseTier_new(0);
    else if (ch == _T('>') && *pCh == _T('<'))
        return CseInstance_new();
    else if (*pCh == _T('%'))
    {
        pCh++;
        TStolenObj obj;
        BuildOneCseObj(obj,_T('%'),*pCh,pArg);
        return Cse_IncRefEx(obj);
    }
    else if (ch == _T('\0'))
    {
        TStolenObj obj;
        BuildOneCseObj(obj,_T('\0'),*pCh,pArg);
        return Cse_IncRefEx(obj);
    }

    // then process normal build
    TStolenObj holder = dummy;
    TStolenObj owners = CseBuff_new(0);
    CseObj owner_ = dummy;
    TCharArray OwnerTypes;

    TXchar prefix = _T('\0');
    while (*pCh != _T('\0'))
    {
        while (*pCh == _T(',')) pCh++;   // ignore ","
        if (*pCh == _T('%'))
        {
            prefix = _T('%');
            pCh++;
        }
        else prefix = _T('\0');
        
        TXchar flag = BuildOneCseObj(holder,prefix,*pCh,pArg);
        pCh++;

        if (owner_ == dummy) // if no receiver, just return single value
        {
            if (flag == _T(']') || flag == _T('}') || flag == _T(')') || flag == _T('>'))
                throw LogObjBuildErr();
            else if (flag == _T('[') || flag == _T('{') || flag == _T('(') || flag == _T('<'))
            {
                CseBuff_append(owners,holder);
                owner_ = holder;
                OwnerTypes += flag;
            }
            else return Cse_IncRefEx(holder);
        }
        else
        {
            if (flag == _T('\0')) // holder is single value, and owner_ must be buff
            {
                CseBuff_append(owner_,holder);
            }
            else if (flag == _T('[') || flag == _T('{') || flag == _T('(') || flag == _T('<'))
            {
                CseBuff_append(owners,holder);
                owner_ = holder;
                OwnerTypes += flag;
            }
            else
            {
                ASSERT_TRUE(flag == _T(']') || flag == _T('}') || flag == _T(')') || flag == _T('>'));

                int TypesLen = OwnerTypes.len();
                if (TypesLen > 0)
                {
                    TXchar LastFlag = OwnerTypes[TypesLen-1];
                    if ( (flag == _T(']') && LastFlag != _T('[')) ||
                         (flag == _T('}') && LastFlag != _T('{')) ||
                         (flag == _T(')') && LastFlag != _T('(')) ||
                         (flag == _T('>') && LastFlag != _T('<')) )
                        throw LogObjBuildErr();
                    else OwnerTypes.truncate(TypesLen-1);
                }
                else throw LogObjBuildErr();

                TStolenObj item = SetupBuildResult(flag,owner_);

                int iLen = CSE_ARRAY_LEN(owners->bValue);
                ASSERT_TRUE(iLen > 0);
                if (iLen == 1)
                {
                    CseBuff_remove(owners,0);
                    return Cse_IncRefEx(item);
                }
                else
                {   // popup one owner level
                    CseBuff_remove(owners,iLen-1);
                    owner_ = owners->bValue[iLen-1]; // owner must be buff
                    ASSERT_TRUE(Cse_type(owner_) == dtBuff);
                    CseBuff_append(owner_,item);
                }
            }
        }
    }

    // build nothing or not normal closed by ']','}',')','>'
    throw LogObjBuildErr();
}

TCseObj TCseObj::format(const TXchar *frmt, ...)
{
    va_list pArg;
    va_start(pArg, frmt);
    TStolenObj v = CreateByFmt(frmt,pArg);
    va_end(pArg);

    return TCseObj((CseObj)v);
}

TCseObj::TCseObj(const TIntObj& iObj)
{
    m_data = CseInt_new(iObj);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TWintObj& wObj)
{
    m_data = CseWint_new(wObj);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TFloatObj& fObj)
{
    m_data = CseFloat_new(fObj);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TCharArray& s)
{
    m_data = CseStr_new(s);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TIntArray& t)
{
    m_data = CseTier_new(t);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TObjArray& b)
{
    m_data = CseBuff_new(b);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(const TEntryArray& d)
{
    m_data = CseDict_new(d);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::~TCseObj()
{
    Cse_DecRef(m_data);
#ifdef _DEBUG
    TotalCseObjCount--;
#endif
}

TCseObj& TCseObj::assign(CseObj obj)
{
    if (NULL == obj) obj = dummy;

    CseObj v = m_data;
    m_data = Cse_IncRefEx(obj);
    Cse_DecRef(v);

    return *this;
}

TCseObj::TCseObj(int MagicNum, TCharArray& s)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = CseStr_NewEx(s);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(int MagicNum, TIntArray& t)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = CseTier_NewEx(t);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(int MagicNum, TObjArray& b)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = CseBuff_NewEx(b);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj::TCseObj(int MagicNum, TEntryArray& d)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));
    m_data = CseDict_NewEx(d);
#ifdef _DEBUG
    TotalCseObjCount++;
#endif
}

TCseObj& TCseObj::operator=(const TCseObj& obj)
{
    CseObj v = m_data;
    m_data = Cse_IncRefEx(obj.m_data);
    Cse_DecRef(v);
    
    return *this;
}

TCseObj& TCseObj::operator=(CseObj obj)
{
    if (NULL == obj) obj = dummy;

    CseObj v = m_data;
    m_data = Cse_IncRefEx(obj);
    Cse_DecRef(v);

    return *this;
}

TCseObj::operator CseObj() const
{
    return Cse_unlink(m_data);
}

CseObj TCseObj::operator->() const
{
    return Cse_unlink(m_data);
}

TIntObj& TCseObj::iObj() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtInt == Cse_type(data),_T("TCseObj.iObj() type invalid: me"));
    return (TIntObj&) data->iValue;
}

TWintObj& TCseObj::wObj() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtWint == Cse_type(data),_T("TCseObj.wObj() type invalid: me"));
    return (TWintObj&) data->wValue;
}

TFloatObj& TCseObj::fObj() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtFloat == Cse_type(data),_T("TCseObj.fObj() type invalid: me"));
    return (TFloatObj&) data->fValue;
}

TCharArray& TCseObj::sArray() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtStr == Cse_type(data),_T("TCseObj.sArray() type invalid: me"));
    return (TCharArray&) data->sValue;
}

TIntArray& TCseObj::tArray() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtTier == Cse_type(data),_T("TCseObj.tArray() type invalid: me"));
    return (TIntArray&) data->tValue;
}

TObjArray& TCseObj::bArray() const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG(tp == dtBuff || tp >= dtNotator,_T("TCseObj.bArray() type invalid: me"));
    return (TObjArray&) data->bValue;
}

TEntryArray& TCseObj::dArray() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtDict == Cse_type(data),_T("TCseObj.dArray() type invalid: me"));
    return (TEntryArray&) data->entry;
}

int TCseObj::len() const
{
    return Cse_len(Cse_unlink(m_data));
}

void TCseObj::clear() const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG(dtBuff == tp || dtInstance == tp || dtDict == tp || dtStr == tp || dtTier == tp,_T("TCseObj.clear() type invalid: me"));
    
    if (dtStr == tp)
        CseStr_clear(data);
    else if (dtTier == tp)
        CseTier_clear(data);
    else if (dtDict == tp)
        CseDict_clear(data);
    else CseBuff_clear(data);
}

TBool TCseObj::fixSize(int iRsvd) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG(dtStr == tp || dtTier == tp || dtBuff == tp || dtDict == tp,_T("TCseObj.fixSize() type invalid: me"));
    return Cse_FixSize(data,iRsvd);
}

void TCseObj::join(const TCseObj& obj, int index) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp || dtDict == tp ||
               dtInstance == tp || tp >= dtNotator,_T("TCseObj.join() type invalid: me"));

    CseObj v = Cse_unlink(obj.m_data);
    if (dtStr == tp)
    {
        CHECK_MSG(dtStr == Cse_type(v),_T("TCseObj.join() type invalid: me"));
        CseStr_join(data,v,index);
    }
    else if (dtTier == tp)
    {
        CHECK_MSG(dtTier == Cse_type(v),_T("TCseObj.join() type invalid: me"));
        CseTier_join(data,v,index);
    }
    else if (dtDict == tp)
    {
        CHECK_MSG(dtDict == Cse_type(v),_T("TCseObj.join() type invalid: me"));
        CseDict_join(data,v);
    }
    else
    {
        tp = Cse_type(v);
        CHECK_MSG(dtBuff == tp || dtInstance == tp || tp >= dtNotator,_T("TCseObj.join() type invalid: me"));
        CseBuff_join(data,v,index);
    }
}

TCseObj TCseObj::slice(int index, int len) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
                dtInstance == tp || tp >= dtNotator,_T("TCseObj.slice() type invalid: me"));

    if (dtStr == tp)
    {
        TStolenObj v = CseStr_slice(data,index,len);
        return (CseObj) v;
    }
    else if (dtTier == tp)
    {
        TStolenObj v = CseTier_slice(data,index,len);
        return (CseObj) v;
    }
    else
    {
        TStolenObj v = CseBuff_slice(data,index,len);
        return (CseObj) v;
    }
}

const TCseObj& TCseObj::append(const TCseObj& obj, int *pIndex) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
                dtInstance == tp || tp >= dtNotator,_T("TCseObj.append() type invalid: me"));

    if (dtStr == tp)
    {
        CseObj obj_ = Cse_unlink(obj.m_data);
        tp = Cse_type(obj_);
        if (tp == dtInt)
            CseStr_append(data,(TXchar)obj_->iValue,pIndex);
        else if (tp == dtWint)
            CseStr_append(data,(TXchar)obj_->wValue,pIndex);
        else if (tp == dtFloat)
            CseStr_append(data,(TXchar)obj_->fValue,pIndex);
        else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("only char can append to string"));
    }
    else if (dtTier == tp)
    {
        CseObj obj_ = Cse_unlink(obj.m_data);
        tp = Cse_type(obj_);
        if (tp == dtInt)
            CseTier_append(data,obj_->iValue,pIndex);
        else if (tp == dtWint)
            CseTier_append(data,(TInt)obj_->wValue,pIndex);
        else if (tp == dtFloat)
            CseTier_append(data,(TInt)obj_->fValue,pIndex);
        else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("only int can append to tier"));
    }
    else CseBuff_append(data,obj.m_data,pIndex);
    
    return obj;
}

const TCseObj& TCseObj::insert(int index, const TCseObj& obj) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
               dtInstance == tp || tp >= dtNotator,_T("TCseObj.insert() type invalid: me"));

    if (dtStr == tp)
    {
        CseObj obj_ = Cse_unlink(obj.m_data);
        tp = Cse_type(obj_);
        if (tp == dtInt)
            CseStr_insert(data,index,(TXchar)obj_->iValue);
        else if (tp == dtWint)
            CseStr_insert(data,index,(TXchar)obj_->wValue);
        else if (tp == dtFloat)
            CseStr_insert(data,index,(TXchar)obj_->fValue);
        else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("only char can insert to string"));
    }
    else if (dtTier == tp)
    {
        CseObj obj_ = Cse_unlink(obj.m_data);
        tp = Cse_type(obj_);
        if (tp == dtInt)
            CseTier_insert(data,index,obj_->iValue);
        else if (tp == dtWint)
            CseTier_insert(data,index,(TInt)obj_->wValue);
        else if (tp == dtFloat)
            CseTier_insert(data,index,(TInt)obj_->fValue);
        else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("only int can insert to tier"));
    }
    else
    {
        CHECK_MSG(dtBuff == tp || index != 0,_T("TCseObj.insert() type invalid: me"));
        CseBuff_insert(data,index,obj.m_data);
    }

    return obj;
}

void TCseObj::remove(int index, int len) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
               dtInstance == tp || tp >= dtNotator,_T("TCseObj.remove() type invalid: me"));

    if (dtStr == tp)
        CseStr_remove(data,index,len);
    else if (dtTier == tp)
        CseTier_remove(data,index,len);
    else
    {
        CHECK_MSG(dtBuff == tp || dtInstance == tp || index != 0,_T("TCseObj.remove() type invalid: me"));
        CseBuff_remove(data,index,len);
    }
}

void TCseObj::truncate(int iLen) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp ||
               dtInstance == tp || tp >= dtNotator,_T("TCseObj.truncate() type invalid: me"));

    if (dtStr == tp)
        CseStr_truncate(data,iLen);
    else if (dtTier == tp)
        CseTier_truncate(data,iLen);
    else if (dtBuff == tp)
        CseBuff_truncate(data,iLen);
    else
    {
        CHECK_MSG(iLen >= 1,_T("TCseObj.truncate() type invalid: me"));
        CseBuff_truncate(data,iLen);
    }
}

void TCseObj::sort() const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG( dtStr == tp || dtTier == tp || dtBuff == tp,_T("TCseObj.sort() type invalid: me"));

    if (dtStr == tp)
        CseStr_sort(data);
    else if (dtTier == tp)
        CseTier_sort(data);
    else CseBuff_sort(data);
}

int TCseObj::type() const
{
    return Cse_type(Cse_unlink(m_data));
}

TCharArray TCseObj::str() const
{
    TCharArray ret;
    CseObj data = Cse_unlink(m_data);
    Cse_str(ret,data);
    return TCharArray(CUT_FROM,ret);
}

TCharArray TCseObj::beStr() const
{
    TCharArray ret;
    CseObj data = Cse_unlink(m_data);
    Cse_BeStr(ret,data);
    return ret;
}

TUint32 TCseObj::hash() const
{
    CseObj data = Cse_unlink(m_data);
    return Cse_hash(data);
}

int TCseObj::compare(const TCseObj& other) const
{
    CseObj data = Cse_unlink(m_data);
    CseObj other_ = Cse_unlink(other.m_data);

    // dummy value will shortcut comparsion
    if (data == dummy)
    {
        if (other_ == dummy)
            return 0;
        else return (int)data - (int)other_;
    }
    else if (other_ == dummy)
        return (int)data - (int)other_;

    else return Cse_ObjComp(data,other_,Cse_type(other_));
}

CseObj TCseObj::transfer(const TCseObj& value)
{
    CseObj ret = m_data;
    m_data = Cse_IncRefEx(value.m_data);
    
    return ret;
}

TBool TCseObj::isMapped() const
{
    return Cse_type(m_data) == dtInstance;
}

TBool TCseObj::isLinked() const
{
    return Cse_OptionOn(m_data,CSEOBJ_LINKED);
}

TInt32 TCseObj::getFlag() const
{
    return Cse_GetFlag(Cse_unlink(m_data));
}

void TCseObj::setFlag(TInt32 flag) const
{
    Cse_SetFlag(Cse_unlink(m_data),flag);
}

TBool TCseObj::optionOn(int iBit) const
{
    return Cse_OptionOn(Cse_unlink(m_data),iBit);
}

void TCseObj::setOption(int iBit) const
{
    Cse_SetOption(Cse_unlink(m_data),iBit);
}

void TCseObj::clearOption(int iBit) const
{
    Cse_ClearOption(Cse_unlink(m_data),iBit);
}

TCseObj TCseObj::toId() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(Cse_type(data) == dtStr,_T("TCseObj.toId() type invalid: me"));
    if (CSE_ARRAY_LEN(data->sValue) == 0)
        throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("try transfer empty string to ID"));

    TCharArray *s = (TCharArray *) &data->sValue;
    if (data == m_data && Cse_RefCount(m_data) == 1)
    {   // quick stolen from current string
        TStolenObj ret = CseId_NewEx(*s);
        return (CseObj) ret;
    }
    else
    {
        TStolenObj ret = CseId_new(*s);
        return (CseObj) ret;
    }
}

TCseObj& TCseObj::operator[](int index) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG( dtBuff == tp || dtInstance == tp || tp >= dtNotator,_T("TCseObj[] type invalid: me"));

    TObjArray& b = (TObjArray&) data->bValue;
    return b[index];
}

TCseObj& TCseObj::sub(int index) const
{
    int tp = Cse_type(m_data);
    CHECK_MSG(dtBuff == tp || dtInstance == tp || tp >= dtNotator,_T("TCseObj.sub() type invalid: me"));

    TObjArray& b = (TObjArray&) m_data->bValue;
    return b[index];
}

TCseObj TCseObj::pop(int index) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(Cse_type(data) == dtBuff,_T("TCseObj.pop() type invalid: me"));

    TObjArray *ObjArray = (TObjArray *) &data->bValue;
    return ObjArray->pop(index);
}

void TCseObj::push(const TCseObj& obj) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(Cse_type(data) == dtBuff,_T("TCseObj.push() type invalid: me"));
    CseBuff_append(data,obj.m_data);
}

TCseObj TCseObj::toNotator(int index) const
{
    CseObj data = Cse_unlink(m_data);
    int tp = Cse_type(data);
    CHECK_MSG(tp == dtBuff || tp >= dtNotator || tp == dtInstance,_T("TCseObj.toNotator() type invalid: me"));

    TStolenObj ret = CseBuff_ToNotator(data,index);
    return (CseObj) ret;
}

TBool TCseObj::isSpace() const
{
    CseObj data = Cse_unlink(m_data);
    return Cse_type(data) == dtDict && data->entry != NULL && data->entry[0].key == constSpace;
}

TCseObj TCseObj::get(const TCseObj& key) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtDict == Cse_type(data),_T("TCseObj.get() type invalid: me"));
    
    TEntryArray *EntryArray = (TEntryArray *) &data->entry;
    return EntryArray->get(key);
}

const TCseObj& TCseObj::set(const TCseObj& key, const TCseObj& value) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG( dtDict == Cse_type(data),_T("TCseObj.set() type invalid: me") );
    TEntryArray *EntryArray = (TEntryArray *) &data->entry;
    return EntryArray->set(key,value);
}

TCseObj TCseObj::quickGet(const TCseObj& key) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtDict == Cse_type(data),_T("TCseObj.quickGet() type invalid: me"));
    CseObj key_ = Cse_unlink(key.m_data);
    CHECK_MSG(dtId == Cse_type(key_),_T("key type of TCseObj.quickGet(key) invalid"));

    TUint32 hash = key_->hash;
    if (hash < CSE_ARRAY_LEN(data->entry))
    {
        PEntryPoint pEntry = data->entry + hash;
        if (pEntry->key == key_)
            return pEntry->value;
    }
    return dummy;
}

TBool TCseObj::quickSet(const TCseObj& key, const TCseObj& value) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtDict == Cse_type(data),_T("TCseObj.quickSet() type invalid: me"));

    if (value == dummy)
    {   // delete key
        TEntryArray *EntryArray = (TEntryArray *) &data->entry;
        EntryArray->set(key,dummy);
        return true;
    }

    CseObj key_ = Cse_unlink(key.m_data);
    CHECK_MSG(dtId == Cse_type(key_),_T("key type of TCseObj.quickSet(key,value) invalid"));

    TUint32 hash = key_->hash;
    PEntryPoint pEntry = data->entry + hash;
    if (pEntry->key == NULL)
    {
        CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *) ((char *)data->entry - sizeof(CSE_DICT_EXT));

        pEntry->value = Cse_IncRefEx(value.m_data);
        pEntry->key = Cse_IncRefEx(key_);
        pEntry->hash = hash;

        pDictExt->FilledCount++;
        pDictExt->count++;

        return true;
    }
    else return false;
}

TBool TCseObj::enumItem(PEntryPoint& pEntry, TCseObj *pKey, TCseObj *pValue) const
{
    CseObj data = Cse_unlink(m_data);
    ASSERT_TRUE(dtDict == Cse_type(data));

    TEntryArray *EntryArray = (TEntryArray *) &data->entry;
    return EntryArray->enumItem(pEntry,pKey,pValue);
}

TCseObj TCseObj::strongGet() const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtStrong == Cse_type(data),_T("TCseObj.strongGet() type invalid: me"));
    return data->vValue;
}

const TCseObj& TCseObj::strongSet(const TCseObj& value) const
{
    CseObj data = Cse_unlink(m_data);
    CHECK_MSG(dtStrong == Cse_type(data),_T("TCseObj.strongSet() type invalid: me"));
    CseStrong_set(data,value.m_data);
    return value;
}

TCseObj Cse_NewTier(int ArgNum, ...)
{
    va_list pArg;
    va_start(pArg, ArgNum);
    
    TIntArray ret;
    for (int iCount = 0; iCount < ArgNum; iCount++)
        ret.append(va_arg(pArg,TInt));
    va_end(pArg);

    return TCseObj(CUT_FROM,ret);
}

TCseObj Cse_NewBuff(int ArgNum, ...)
{
    va_list pArg;
    va_start(pArg, ArgNum);
    
    TObjArray ret;
    for (int iCount = 0; iCount < ArgNum; iCount++)
        ret.append(va_arg(pArg,CseObj));
    va_end(pArg);

    return TCseObj(CUT_FROM,ret);
}

TCseObj Cse_NewDict(int ArgNum, ...)
{
    CHECK_MSG((ArgNum & 0x01) != 1, _T("argument number of Cse_NewDict() error"));

    va_list pArg;
    va_start(pArg, ArgNum);
    
    TEntryArray ret;
    for (int iCount = 1; iCount < ArgNum; iCount += 2)
    {
        TCseObj key = va_arg(pArg,CseObj);
        TCseObj value = va_arg(pArg,CseObj);
        ret.set(key,value);
    }
    va_end(pArg);

    return TCseObj(CUT_FROM,ret);
}

TBool operator==(TCseObj& obj1, TCseObj& obj2)
{
    CseObj other = obj2;       // unlink it
    if (other == dummy)
    {
        CseObj data = obj1;    // unlink it
        return data == dummy;
    }
    else
    {
        CseObj data = obj1;    // unlink it
        if (data == dummy)     // obj1 == dummy && obj2 != dummy
            return false;
        else return Cse_equal(data,other);
    }
}

TBool operator==(TCseObj& obj1, CseObj obj2)
{
    if (obj2 == dummy || obj2 == NULL)
    {
        CseObj data = obj1;    // unlink it
        return data == dummy;
    }
    else
    {
        CseObj data = obj1;    // unlink it
        if (data == dummy)     // obj1 == dummy && obj2 != dummy
            return false;
        else return Cse_equal(data,obj2);
    }
}

TBool operator==(CseObj obj1, TCseObj& obj2)
{
    if (obj1 == dummy || obj1 == NULL)
    {
        CseObj other = obj2;
        return other == dummy;
    }
    else
    {
        CseObj other = obj2;   // unlink it
        if (other == dummy)
            return false;
        else return Cse_equal(obj1,other);
    }
}

TBool operator!=(TCseObj& obj1, TCseObj& obj2)
{
    CseObj other = obj2;
    if (other == dummy)
    {
        CseObj data = obj1;
        return data != dummy;
    }
    else
    {
        CseObj data = obj1;
        if (data == dummy)    // obj1 == dummy && obj2 != dummy
            return true;
        else return !Cse_equal(data,other);
    }
}

TBool operator!=(TCseObj& obj1, CseObj obj2)
{
    if (obj2 == dummy || obj2 == NULL)
    {
        CseObj data = obj1;
        return data != dummy;
    }
    else
    {
        CseObj data = obj1;  // unlink it
        if (data == dummy)   // obj1 == dummy && obj2 != dummy
            return true;
        else return !Cse_equal(data,obj2);
    }
}

TBool operator!=(CseObj obj1, TCseObj& obj2)
{
    if (obj1 == dummy || obj1 == NULL)
    {
        CseObj other = obj2;
        return other != dummy;
    }
    else
    {
        CseObj other = obj2;  // unlink it
        if (other == dummy)
            return true;
        else return !Cse_equal(obj1,other);
    }
}

TBool operator>(TCseObj& obj1, TCseObj& obj2)
{
    return obj1.compare(obj2) > 0;
}

TBool operator>(TCseObj& obj1, CseObj obj2)
{
    return obj1.compare(obj2) > 0;
}

TBool operator>(CseObj obj1, TCseObj& obj2)
{
    return obj2.compare(obj1) < 0;
}

TBool operator>=(TCseObj& obj1, TCseObj& obj2)
{
    return obj1.compare(obj2) >= 0;
}

TBool operator>=(TCseObj& obj1, CseObj obj2)
{
    return obj1.compare(obj2) >= 0;
}

TBool operator>=(CseObj obj1, TCseObj& obj2)
{
    return obj2.compare(obj1) <= 0;
}

TBool operator<(TCseObj& obj1, TCseObj& obj2)
{
    return obj1.compare(obj2) < 0;
}

TBool operator<(TCseObj& obj1, CseObj obj2)
{
    return obj1.compare(obj2) < 0;
}

TBool operator<(CseObj obj1, TCseObj& obj2)
{
    return obj2.compare(obj1) > 0;
}

TBool operator<=(TCseObj& obj1, TCseObj& obj2)
{
    return obj1.compare(obj2) <= 0;
}

TBool operator<=(TCseObj& obj1, CseObj obj2)
{
    return obj1.compare(obj2) <= 0;
}

TBool operator<=(CseObj obj1, TCseObj& obj2)
{
    return obj2.compare(obj1) >= 0;
}
